package com.jiyinit.web.core.business.controller;

import com.jiyinit.core.framework.base.entity.ResponseDto;
import com.jiyinit.core.framework.base.util.Check;
import com.jiyinit.web.core.common.config.PropertyPlaceholderConfigurer;
import com.jiyinit.web.core.common.util.Md5Util;
import com.jiyinit.web.core.common.util.ZipUtil;
import com.jiyinit.web.core.mobile.util.FilesUtil;
import org.apache.commons.fileupload.FileItem;
import org.apache.shiro.crypto.hash.Hash;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Created by user1 on 2019/2/14.
 */
@Controller
@RequestMapping(value = "/deploy")
public class DeployFilesController {

    private static final int resetNum = 1000*60*24;

    private static final String line = File.separator;

    private static final Logger LOGGER = LoggerFactory.getLogger(DeployFilesController.class);

//    static {
//        new Timer().schedule(new TimerTask() {
//            @Override
//            public void run() {
//                //startNum = 0;
//                System.out.println("重置启动次数....");
//            }
//        }, resetNum , resetNum);
//    }

    @RequestMapping(value = "/todeploy")
    public String todeploy(){
        return "deploy/deploy";
    }

    /**
     * 重启tomcat服务
     * @return
     * @throws Exception
     */
    @ResponseBody
    @RequestMapping(value = "/restartTomcat")
    public ResponseEntity<ResponseDto> restartTomcat(){
        if(isLinux()){
            try {
                String command = "java -cp RestartCmd-1.0-SNAPSHOT.jar com.txd.pro.App";
                String dir = (String) PropertyPlaceholderConfigurer.getContextProperty("RESART_CMD_URL");
                System.out.println("重启命令: "+command+"\n脚本路径: "+dir);
                Process process = exec(command, null, dir);
                int i = process.waitFor();
                if(i == 0){
                    process.destroy();
                    return new ResponseEntity<>(ResponseDto.responseOK(""), HttpStatus.OK);
                }
            } catch (Exception e){
                e.printStackTrace();
                LOGGER.info("e: {}", e.getMessage());
                return new ResponseEntity<>(ResponseDto.responseFail(e.getMessage()), HttpStatus.OK);
            }
        }
        //return new ResponseEntity<>(ResponseDto.responseOK(""), HttpStatus.OK);
        return new ResponseEntity<>(ResponseDto.responseFail("请在<a href='http://192.168.0.107:8091/login'>测试环境</a>执行此命令"), HttpStatus.OK);
    }

    @RequestMapping(value = "/toDeployFiles")
    public String toDeployFiles(){
        return "deploy/deployFiles";
    }

    /**
     * 部署上线包
     * @return
     * @throws Exception
     */
    @ResponseBody
    @RequestMapping(value = "/deployFiles")
    public synchronized ResponseEntity<ResponseDto> deployFiles(HttpServletRequest request){
        String isCheck = request.getParameter("isCheck");
        String pwd = request.getParameter("pwd");
        List<MultipartFile> multipartFileList = getMultipartFileList(request);//获取上传文件列表
        String projectPath = request.getSession().getServletContext().getRealPath("");//获取项目绝对路径

        String successInfo = "";
        if("true".equals(isCheck)){
            String deploy_pwd = (String) PropertyPlaceholderConfigurer.getContextProperty("DEPLOY_PWD");
            try{
                pwd = Md5Util.encode(pwd);
                if(deploy_pwd.equals(pwd)){
                    String bakUrl = (String) PropertyPlaceholderConfigurer.getContextProperty("PROJECT_BACKUP_URL");//项目备份路径
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
                    HashSet<String> urls = getFilesSet(projectPath);

                    bakUrl = bakUrl + sdf.format(new Date()) + "_bak.zip";
                    LOGGER.info("开始备份项目, 项目路径: {}, 本次备份路径: {}", projectPath, bakUrl);
                    try {
                        FilesUtil.createDirectoryAndFile(bakUrl);
                        ZipUtil.toZip(projectPath, bakUrl, true);//全量备份
                    } catch (Exception e) {
                        e.printStackTrace();
                        LOGGER.error("e: {}", e.getMessage());
                        return new ResponseEntity<>(ResponseDto.responseFail("备份项目失败! 部署已经终止"), HttpStatus.OK);
                    }

                    int addNum = 0;
                    int sameNum = 0;
                    for (MultipartFile mfile : multipartFileList) {
                        CommonsMultipartFile cfile = (CommonsMultipartFile) mfile;
                        FileItem fileItem = cfile.getFileItem();
                        String name = fileItem.getName();
                        if (!isLinux()) {
                            name = name.replaceAll("/", "\\\\");
                        }
                        name = projectPath + name.substring(name.indexOf(line), name.length());
                        File dest = new File(name);
                        if (!urls.contains(name)) {
                            LOGGER.info("覆盖文件: {}", name);
                            //mfile.transferTo(dest);
                            addNum++;
                        } else {
                            LOGGER.info("新增文件: {}", name);
                            //mfile.transferTo(dest);
                            sameNum++;
                        }
                    }
                    successInfo = "部署完成! 本次覆盖"+addNum+"个文件, 新增"+sameNum+"个文件.";
                    LOGGER.debug("部署完成! 本次覆盖{}个文件, 新增{}个文件.==================", addNum, sameNum);
                }else{
                    return new ResponseEntity<>(ResponseDto.responseFail("口令错误! 部署已经终止"), HttpStatus.OK);
                }
            }catch (Exception e){
                e.printStackTrace();
                LOGGER.error("e: {}", e.getMessage());
                return new ResponseEntity<>(ResponseDto.responseFail("部署异常! 请检查项目, 并手动还原."), HttpStatus.OK);
            }
        }else{
            return checkUploadPackage(projectPath, multipartFileList);
        }
        return new ResponseEntity<>(ResponseDto.responseOK(successInfo), HttpStatus.OK);
    }

//    public int deployPackage(){
//
//    }

    /**
     * 检验上线包
     * @param projectPath
     * @param multipartFileList
     * @return
     */
    public ResponseEntity<ResponseDto> checkUploadPackage(String projectPath, List<MultipartFile> multipartFileList){
        LOGGER.info("开始检测上线包.....");
        if(!Check.isNullCollection(multipartFileList)){
            LOGGER.info("开始分析项目结构...............");
            Set<String> urls = getFilesSet(projectPath);
            if(!Check.isNullCollection(urls)){
                int addNum = 0;
                int sameNum = 0;
                for (MultipartFile mfile : multipartFileList) {
                    CommonsMultipartFile cfile = (CommonsMultipartFile) mfile;
                    FileItem fileItem = cfile.getFileItem();
                    String name = fileItem.getName();
                    if(!isLinux()){
                        name = name.replaceAll("/", "\\\\");
                    }
                    name = projectPath + line + name;
                    if(!urls.contains(name)){
                        addNum++;
                    }else{
                        sameNum++;
                    }
                }
                return new ResponseEntity<>(ResponseDto.responseOK("你本次新增"+addNum+"个文件, 覆盖"+sameNum+"个文件, 是否开始部署?"), HttpStatus.OK);
            }else{
                return new ResponseEntity<>(ResponseDto.responseFail("分析项目结构失败, 请用ftp工具手动检查项目完整性"), HttpStatus.OK);
            }
        }else{
            return new ResponseEntity<>(ResponseDto.responseFail("你本次上传文件数量为0, 你在逗我玩?!"), HttpStatus.OK);
        }
    }

    public HashSet<String> getFilesSet(String realPath){
        HashSet<String> fileNameSet = new HashSet<>();
        File file = new File(realPath);
        fillFiles(file, fileNameSet);
        if(Check.isNullCollection(fileNameSet)){
            return null;
        }
        return fileNameSet;
    }

    public void fillFiles(File file, Set<String> set){
        if(file.isDirectory()){
            File[] files = file.listFiles();
            for (File f: files) {
                fillFiles(f, set);
            }
        }else{
            set.add(file.getPath());
        }
    }


    /**
     * 获取当前请求中的文件列表
     *
     * @param request
     * @return
     */
    private static List<MultipartFile> getMultipartFileList(HttpServletRequest request) {
        List<MultipartFile> files = new ArrayList<MultipartFile>();
        try {
            CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(request.getSession().getServletContext());
            if (request instanceof MultipartHttpServletRequest) {
                // 将request变成多部分request
                MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
                Iterator<String> iter = multiRequest.getFileNames();
                // 检查form中是否有enctype="multipart/form-data"
                if (multipartResolver.isMultipart(request) && iter.hasNext()) {
                    // 获取multiRequest 中所有的文件名
                    while (iter.hasNext()) {
                        // 一次遍历所有文件
                        // MultipartFile file =
                        // multiRequest.getFile(iter.next().toString());
                        // if (file != null) {
                        // files.add(file);
                        // }
                        // 适配名字重复的文件
                        List<MultipartFile> fileRows = multiRequest.getFiles(iter.next());
                        if (fileRows != null && fileRows.size() != 0) {
                            for (MultipartFile file : fileRows) {
                                if (file != null && !file.isEmpty()) {
                                    files.add(file);
                                }
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            LOGGER.error("解析MultipartRequest错误", e);
        }
        return files;
    }



    /**
     *
     * @Title: exec
     * @Description: 简化执行命令行
     * @param  command 命令行
     * @param  envp 环境变量
     * @param  dir  路径
     * @return Process    返回类型
     * @throws IOException
     */
    public static Process exec(String command, String envp, String dir)
            throws IOException {
        String regex = "\\s+";
        String args[] = null;
        String envps[] = null;
        if (!"".equals(command) && command != null) {
            args = command.split(regex);
        }

        if (!"".equals(envp) && envp != null) {
            envps = envp.split(regex);
        }

        return Runtime.getRuntime().exec(args, envps, new File(dir));

    }

    /**
     * 检测系统环境
     * @return
     */
    public boolean isLinux(){
        String osName = System.getProperty("os.name");
        System.out.println(osName);
        if (osName != null && osName.toLowerCase().contains("linux")) {
            return true;
        } else {
            return false;
        }
    }
}
